package com.sqtracker.recommender.util;

import java.util.HashSet;
import java.util.Map;
import java.util.Set;

/**
 * 向量相似度计算工具类
 */
public class VectorUtil {

    /**
     * 计算两个向量的余弦相似度
     * 公式: cos(θ) = (A·B)/(|A|×|B|)
     * @param vector1 向量1
     * @param vector2 向量2
     * @return 相似度 (0-1)
     */
    public static double cosineSimilarity(Map<String, Double> vector1, Map<String, Double> vector2) {
        if (vector1.isEmpty() || vector2.isEmpty()) {
            return 0.0;
        }

        double dotProduct = 0.0;
        double norm1 = 0.0;
        double norm2 = 0.0;

        // 创建属性并集
        Set<String> features = new HashSet<>(vector1.keySet());
        features.addAll(vector2.keySet());

        // 计算点积和模长平方
        for (String feature : features) {
            double value1 = vector1.getOrDefault(feature, 0.0);
            double value2 = vector2.getOrDefault(feature, 0.0);

            dotProduct += value1 * value2;
            norm1 += value1 * value1;
            norm2 += value2 * value2;
        }

        // 避免除零
        if (norm1 <= 0.0 || norm2 <= 0.0) {
            return 0.0;
        }

        return dotProduct / (Math.sqrt(norm1) * Math.sqrt(norm2));
    }

    /**
     * 欧几里得距离
     * @param vector1 向量1
     * @param vector2 向量2
     * @return 距离值
     */
    public static double euclideanDistance(Map<String, Double> vector1, Map<String, Double> vector2) {
        double sum = 0.0;

        // 创建属性并集
        Set<String> features = new HashSet<>(vector1.keySet());
        features.addAll(vector2.keySet());

        // 计算平方和
        for (String feature : features) {
            double value1 = vector1.getOrDefault(feature, 0.0);
            double value2 = vector2.getOrDefault(feature, 0.0);

            double diff = value1 - value2;
            sum += diff * diff;
        }

        return Math.sqrt(sum);
    }

    /**
     * 将欧几里得距离转换为相似度分数
     * @param distance 距离值
     * @return 相似度 (0-1)
     */
    public static double distanceToSimilarity(double distance) {
        return 1.0 / (1.0 + distance);
    }
}